﻿//
// Created by hujin on 2020/10/6.
//

#ifndef C_MIPS_CMPLR_AST_EXPRS_H
#define C_MIPS_CMPLR_AST_EXPRS_H

#include "ast.h"


class TermNode : public  ASTNode {
	std::vector<std::pair<bool, FactorNode*>> factors;//true->multiply
	int tempIndex = 0;
public:
    bool returnConstant(int& val);
    bool isReturnInt();

	explicit TermNode(std::vector<std::pair<bool, FactorNode*>> factors) : factors(std::move(factors)) {}

    int genCode(Synthesizer *pSynthesizer, MemoryAllocator *pAllocator, int var_target);
	void addToTable(SymbolTable *table) override{
        tempIndex = table->gettempVarID();
	}

    std::set<int> getUseVarIndex();
};

class FactorNode : public  ASTNode {
	int val = 0; bool isInt = false;
public:
    virtual bool isReturnInt_Factor();
    virtual bool returnConstant(int& v) {v = this->val;return true;}

	explicit FactorNode(int val) : val(val) , isInt(true){}

	explicit FactorNode(char val) : val((int)val), isInt(false) {}

    virtual int genCode(Synthesizer *pSynthesizer, MemoryAllocator *pAllocator, int var_target);

    virtual std::set<int> getFactorUseVarIndex() {return {};};
protected:
	FactorNode() = default;
};

class ExprNode : public  FactorNode {
	std::vector<std::pair<bool, TermNode*>> terms; // true->plus
    int tempIndex = 0;
    bool calced = false;int cnstVal = 0;
public:
    bool returnConstant(int& v) override;
    int genCode(Synthesizer *out, MemoryAllocator *allocator, int var_index) override ;

    bool isReturnInt() ;
    bool isReturnInt_Factor() override {return true;};
	explicit ExprNode(std::vector<std::pair<bool, TermNode*>> terms) : terms(std::move(terms)) {}
    void addToTable(SymbolTable *table) override{
        tempIndex = table->gettempVarID();
    }

    std::set<int> getUseVarIndex();

	std::set<int> getFactorUseVarIndex() override{return getUseVarIndex();}

};

class IdentiferFactor : public FactorNode {
	std::string name;
	Identifier_Data defineDat;
	int dimension = 0;
	ExprNode* dimension1 = nullptr, * dimension2 = nullptr;
	int varIndexTemp = 0, varIndexTemp2 = 0 ;
public:
    bool isReturnInt_Factor() override ;
    bool returnConstant(int& val) override;
	explicit IdentiferFactor(std::string& name) : name(std::move(name)) {}

	IdentiferFactor(std::string& name, int dimension, ExprNode* dimension1, ExprNode* dimension2)
		: name(std::move(name)), dimension1(dimension1), dimension2(dimension2), dimension(dimension) {};
	bool checkError(SymbolTable *symbolTable) override;

	Identifier_Data getData(){
	    return defineDat;
	}
    void addToTable(SymbolTable* table) override{
	    defineDat = table->getDiscriptions(name);
	    varIndexTemp = table->gettempVarID();
        varIndexTemp2 = table->gettempVarID();
	};

	std::set<int> getFactorUseVarIndex() override{
	    if(isArr()){
            std::set<int> ret = dimension1->getUseVarIndex();
            if(dimension == 1)return ret;
            const std::set<int> & s = dimension2->getUseVarIndex();
            ret.insert(s.begin(), s.end());
            return ret;
	    }
	    return {defineDat.uid};
	}

    bool isArr() const{return dimension > 0;}

    int genCode(Synthesizer *out, MemoryAllocator *allocator, int var_index) override ;
	//int codeLoadR(Synthesizer *out, MemoryAllocator *allocator);
    int getVarIndex() const{return defineDat.uid;};

    void codeSaveArr(Synthesizer *out, MemoryAllocator *allocator, int var_index);//Require isArr()
    void codeSaveCnst(Synthesizer *out, MemoryAllocator *allocator, int cnst);//Require isArr()

};

class FunctionCallFactor : public FactorNode {
	FuncCallNode* callNode;
	Identifier_Data defindDat;
public:
    bool isReturnInt_Factor() override ;
    bool returnConstant(int&) override{return false;};
	explicit FunctionCallFactor(FuncCallNode* callNode) : callNode(callNode) {}
    void addToTable(SymbolTable* table) override;

	int genCode(Synthesizer *pSynthesizer, MemoryAllocator *pAllocator, int var_target) override;

	std::set<int> getFactorUseVarIndex() override;

};


#endif //C_MIPS_CMPLR_AST_EXPRS_H
